package http2

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"
)

type Header struct {
	Key   string
	Value string
}

type Req struct {
	Param    io.Reader
	Headers  []Header
	Timeout  time.Duration
	UserName string
	PassWord string
	Err      error
}

const (
	ContentTypeJson = "application/json"
	ContentTypeForm = "application/x-www-form-urlencoded"
	CharsetUTF8     = ";charset=UTF-8"
	MethodGet       = "GET"
	MethodPost      = "POST"
	MethodPut       = "PUT"
	MethodDelete    = "DELETE"
	UAWindowsChrome = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
)

type Option func(*Req)

func AddHeader(key string, value string) Option {
	return func(req *Req) {
		req.Headers = append(req.Headers, Header{Key: key, Value: value})
	}
}

func ContentType(t string, charset ...string) Option {
	return func(req *Req) {
		var ct = t
		if len(charset) == 1 {
			ct += charset[0]
		}
		req.Headers = append(req.Headers, Header{Key: "Content-Type", Value: t})
	}
}

func UserAgent(ua string) Option {
	return func(req *Req) {
		req.Headers = append(req.Headers, Header{Key: "User-Agent", Value: ua})
	}
}

func TimeOut(t time.Duration) Option {
	return func(req *Req) {
		req.Timeout = t
	}
}

func FormParam(param map[string]string) Option {
	return func(req *Req) {
		formValues := url.Values{}
		for k, v := range param {
			formValues.Set(k, v)
		}
		req.Param = strings.NewReader(formValues.Encode())
	}
}

func JsonParam(param any) Option {
	return func(req *Req) {
		reqBody, err := json.Marshal(param)
		req.Param = bytes.NewBuffer(reqBody)
		req.Err = err
	}
}

func Auth(username, password string) Option {
	return func(req *Req) {
		req.UserName = username
		req.PassWord = password
	}
}

func Request(method string, url string, options ...func(*Req)) ([]byte, error) {
	var result []byte
	req := Req{
		Param:    nil,
		Headers:  nil,
		Timeout:  120 * time.Second,
		UserName: "",
		PassWord: "",
		Err:      nil,
	}
	for _, option := range options {
		option(&req)
	}
	if req.Err != nil {
		return result, req.Err
	}
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr, Timeout: req.Timeout}
	// fmt.Println("param:", req.Param)
	request, err := http.NewRequest(method, url, req.Param)
	if err != nil {
		return result, err
	}
	if req.UserName != "" && req.PassWord != "" {
		request.SetBasicAuth(req.UserName, req.PassWord)
	}
	for _, h := range req.Headers {
		request.Header.Set(h.Key, h.Value)
	}
	response, err := client.Do(request)
	if err != nil {
		return result, err
	}
	defer response.Body.Close()
	result, err = io.ReadAll(response.Body)
	// fmt.Println("result:", string(result))
	return result, err
}

func RequestJsonUnmarshal(method string, url string, result any, options ...func(*Req)) error {
	dataBody, err := Request(method, url, options...)
	if err != nil {
		return err
	}
	return json.Unmarshal(dataBody, &result)
}

func IsUrl(u string) bool { // 判断是否是url
	_, err := url.ParseRequestURI(u)
	return err == nil
}
